package com.qf.boot2202day03.service.impl;


import cn.hutool.crypto.digest.DigestUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.qf.boot2202day03.dao.UserDao;
import com.qf.boot2202day03.entity.User;
import com.qf.boot2202day03.service.UserSevice;
import com.qf.boot2202day03.utils.Constants;
import com.qf.boot2202day03.vo.ResultVo;
import com.qf.boot2202day03.vo.TableVo;
import com.qf.boot2202day03.vo.UserVo;
import com.qf.qfsyspringbootstarter.utils.QfFileAppender;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@Service
@Slf4j
public class UserSeviceImpl implements UserSevice {

    @Autowired
    private UserDao userDao;

    @Value("${file.upload.dir}")
    private String uploaddir;

    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public User getUser(Integer id) {

        return userDao.getUserById(id);

    }

    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public User login(String username, String password) {
        log.debug("userservice查询用户收到的参数为username={},passowrd={}",username,password);

        //1. 根据用户名查询用户
        User user =  userDao.getUserByName(username);

        if (user == null){
            return null;
        }

        //2. 比对数据库中的密码和登录表单中传递的密码是否一致

        // 把用户传递的password进行md5转换
        final String md5Password = DigestUtil.md5Hex(password);

        if (md5Password.equals(user.getPassword())){
            return user;
        }else {
            return null;
        }

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public ResultVo regist(UserVo userVo, String realPath) throws IOException {

        log.debug("开始保存头像文");
        final MultipartFile file1 = userVo.getFile1();
        //1. 生成一个唯一的文件名 ： 唯一前缀 + 原始文件名
        final String prefix = UUID.randomUUID().toString();

        final String originalFilename = file1.getOriginalFilename();
        final String extension = FilenameUtils.getExtension(originalFilename);
        final String finalFileName = prefix +"."+ extension;

        final String finalFilePath = realPath + File.separator + finalFileName;

        // 判断 realPath 对应的目录是否存在，如果不存在则创建
        final File dir = new File(realPath);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        // 存文件
        file1.transferTo(new File(finalFilePath));
        log.debug("保存头像文件成功:finalFilePath={}",finalFilePath);

        log.debug("保存用户的注册信息到数据库中");
        // userVo  ----- >  user
        final User user = new User();

        // 从一个对象中拷贝相同属性到另一个对象中
        BeanUtils.copyProperties(userVo,user);


        // 补全剩下的属性
        user.setName(userVo.getUsername());
        user.setRegistTime(new Date());
        user.setPhotopath(finalFileName);

        // 处理密码加密
//        user.setPassword();
        final String md5password = DigestUtil.md5Hex(userVo.getPassword());
        user.setPassword(md5password);
        log.debug("保存的用户信息为:user={}",user);
        userDao.insertUser(user);
        log.debug("保存用户成功");
        return new ResultVo(Constants.SUCCESS_CODE,"注册用户成功");
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public ResultVo checkUsername(String username) {

        final User user = userDao.getUserByName(username);

        if (user == null){
            // 用户名不存在
            return new ResultVo(Constants.SUCCESS_CODE, "用户名不存在");
        }else {
            return new ResultVo(Constants.FAIL_CODE, "用户名已经存在了");
        }

    }

    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public TableVo getAllUserByPage(Integer page, Integer limit) {

        // 查询user总条数
        Integer count =  userDao.selectCount();

        // 查询当前页的用户数据

        final Integer start = (page - 1) * limit;  // 计算分页的起始行号

        List<User> users =  userDao.selectUserByPage(start,limit);


        final TableVo<User> userTableVo = new TableVo<>();

        userTableVo.setCode(0);
        userTableVo.setMsg("OK");
        userTableVo.setData(users);
        userTableVo.setCount(count);

        return userTableVo;
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public User restoreUser(String username, String md5password) {
        log.debug("userservice查询用户收到的参数为username={},md5password={}",username,md5password);

        //1. 根据用户名查询用户
        User user =  userDao.getUserByName(username);

        if (user == null){
            return null;
        }

        //2. 比对数据库中的密码和登录表单中传递的密码是否一致

        if (md5password.equals(user.getPassword())){
            return user;
        }else {
            return null;
        }
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public TableVo getUserByPagehelper(Integer page, Integer limit) {

        PageHelper.startPage(page,limit);
        final List<User> users = userDao.getAllUser();
        final PageInfo<User> pageInfo = new PageInfo<>(users);
        final long count = pageInfo.getTotal();

        return TableVo.ok((int)count,users);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public ResultVo addUser(User user) {

        // 要把密码进行md5处理
        final String password = user.getPassword();

        final String md5Password = DigestUtil.md5Hex(password);

        user.setPassword(md5Password);

        user.setRegistTime(new Date());

        final Integer result = userDao.insertUser(user);

        return new ResultVo(Constants.SUCCESS_CODE, "添加用户成功");

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public ResultVo deleteUserByIds(List<Integer> ids) {

        userDao.deleteUserByIds(ids);

        return new ResultVo(Constants.SUCCESS_CODE, "删除用户成功");
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public ResultVo updateUser(User user) {

        // 对于密码的处理
        final String password = user.getPassword();

        // 查询数据库中的用户信息
        final User dbuser = userDao.getUserById(user.getId());

        final String dbpassword = dbuser.getPassword();

        if (!dbpassword.equals(password)){
            log.debug("用户修改了密码，重新进行md5预算");
            final String md5password = DigestUtil.md5Hex(password);
            user.setPassword(md5password);
        }

        userDao.updateUser(user);

        return new ResultVo(Constants.SUCCESS_CODE, "修改用户成功");
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public TableVo<User> getUsersByContdition(Integer page, Integer limit, UserVo userVo) {

        PageHelper.startPage(page,limit);
        List<User> data =  userDao.getUsersByContdition(userVo);
        final PageInfo<User> pageInfo = new PageInfo<>(data);
        final long total = pageInfo.getTotal();

        return TableVo.ok((int) total,data);
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public String export() throws IOException {

        //1. 查询所有用户数据
        final List<User> allUser = userDao.getAllUser();

        //2. 把 List<User>  ---->  List<String>

        final List<String> list = allUser.stream().  // list ---> stream
                map(user -> user.toCsvString()).  // stream api 调用
                collect(Collectors.toList());  // stream ---> list

        //3. List<String>  --->  users.csv

        //为每次导出的文件生成一个唯一的文件名，避免多用户同时下载时写同一个文件
        final String filename = UUID.randomUUID().toString()+".csv";

        final String finalFilepath = uploaddir + File.separator + filename;

        final QfFileAppender qfFileAppender = new QfFileAppender(finalFilepath);

        qfFileAppender.appendListToFile(list);

        qfFileAppender.close();

        return filename;
    }
}
